<template>
  <div>
    <div class="float-debug-btn" @click="openDebugDrawer">
      <el-button type="primary" circle>
        <el-icon><DataAnalysis /></el-icon>
      </el-button>
      <span class="btn-tooltip">接口调试</span>
    </div>
    
    <el-drawer
      v-model="isDebugDrawerVisible"
      title="接口调试"
      size="50%"
      :destroy-on-close="false"
    >
      <div class="debug-drawer-content">
        <div class="debug-section">
          <h3>请求信息</h3>
          <div class="debug-info">
            <p><strong>请求URL：</strong>{{ props.requestUrl }}</p>
            <p><strong>请求方式：</strong>{{ props.requestType }}</p>
            <p><strong>Content-Type：</strong>{{ contentTypeLabel }}</p>
          </div>
        </div>
        
        <div class="debug-section">
          <h3>请求头</h3>
          <div class="debug-code-block">
            <pre>{{ formattedHeaders }}</pre>
          </div>
        </div>
        
        <el-button 
          type="primary" 
          @click="sendDebugRequest" 
          :loading="isLoading" 
          style="margin: 20px 0;"
        >
          发送请求
        </el-button>
        
        <div class="debug-section">
          <el-tabs v-model="requestBodyTab">
            <el-tab-pane label="请求体" name="body">
              <div class="debug-code-block">
                <pre>{{ formattedBody }}</pre>
              </div>
            </el-tab-pane>
            <el-tab-pane label="请求日志" name="log" v-if="requestLog.length > 0">
              <div class="debug-log-block" ref="logBlock">
                <p v-for="(log, index) in requestLog" :key="index" :class="log.type">
                  <span class="log-time">[{{ log.time }}]</span> {{ log.message }}
                </p>
              </div>
            </el-tab-pane>
          </el-tabs>
        </div>
        
        <div class="debug-section response-section" v-if="responseStatus !== null">
          <h3>响应信息</h3>
          <div class="response-info">
            <p>
              <strong>状态码：</strong>
              <span :class="responseStatus >= 200 && responseStatus < 300 ? 'success-status' : 'error-status'">
                {{ responseStatus }}
              </span>
            </p>
            <p v-if="responseTime"><strong>响应时间：</strong>{{ responseTime }}ms</p>
          </div>
          <el-tabs v-model="responseTab">
            <el-tab-pane label="响应数据" name="data">
              <div class="debug-code-block response-block response-area" ref="responseBlock">
                <pre v-if="responseData">{{ typeof responseData === 'object' ? JSON.stringify(responseData, null, 2) : responseData }}</pre>
                <pre v-else>暂无响应数据</pre>
              </div>
            </el-tab-pane>
            <el-tab-pane label="响应头" name="headers" v-if="responseHeaders">
              <div class="debug-code-block response-block">
                <template v-if="responseHeaders">
                  <div v-for="(value, key) in formatHeaders(responseHeaders)" :key="key" class="header-item">
                    <strong>{{ key }}:</strong> {{ value }}
                  </div>
                </template>
                <pre v-else>暂无响应头</pre>
              </div>
            </el-tab-pane>
          </el-tabs>
        </div>
        
        <!-- 滚动按钮容器 -->
        <div class="scroll-buttons" v-if="showBackToTop || showScrollToBottom">
          <div class="back-to-top" v-show="showBackToTop" @click="scrollToTop">
            <el-icon><CaretTop /></el-icon>
          </div>
          <div class="scroll-to-bottom" v-show="showScrollToBottom" @click="scrollToBottomOfDrawer">
            <el-icon><CaretBottom /></el-icon>
          </div>
        </div>
      </div>
    </el-drawer>
  </div>
</template>

<script setup>
import { ref, computed, reactive, onMounted, onUnmounted, nextTick, watch } from 'vue'
import http from '@/utils/request'
import axios from 'axios'
import { ElMessage } from 'element-plus'
import { CaretTop, CaretBottom, DataAnalysis } from '@element-plus/icons-vue'

const props = defineProps({
  requestUrl: {
    type: String,
    required: true
  },
  requestType: {
    type: String,
    required: true
  },
  contentType: {
    type: String,
    required: true
  },
  requestHeaders: {
    type: Object,
    default: () => ({})
  },
  requestBody: {
    type: [Object, String],
    default: () => ({})
  }
})

// 抽屉状态
const isDebugDrawerVisible = ref(false)
// 请求响应相关
const responseData = ref(null)
const responseStatus = ref(null)
const responseTime = ref(null)
const responseHeaders = ref(null)
const isLoading = ref(false)
const responseTab = ref('data')
const requestBodyTab = ref('body')
const requestLog = ref([])

// 滚动相关
const drawerContent = ref(null)
const showBackToTop = ref(false)
const showScrollToBottom = ref(false)
const scrollY = ref(0)
const responseBlock = ref(null)
const logBlock = ref(null)

// DOM元素引用字符串常量
const SELECTORS = {
  DRAWER_BODY: '.el-drawer__body',
  RESPONSE_SECTION: '.debug-section:last-child',
  RESPONSE_AREA: '.response-block'
}

// 计算属性：格式化的请求头
const formattedHeaders = computed(() => {
  try {
    return JSON.stringify(props.requestHeaders, null, 2)
  } catch (error) {
    return '{}'
  }
})

// 计算属性：格式化的请求体
const formattedBody = computed(() => {
  try {
    if (props.contentType === 'application/json') {
      if (typeof props.requestBody === 'string') {
        // 尝试解析和格式化JSON
        return JSON.stringify(JSON.parse(props.requestBody), null, 2);
      } else {
        return JSON.stringify(props.requestBody, null, 2);
      }
    } else if (props.contentType === 'application/x-www-form-urlencoded') {
      // 如果是form类型，尝试将其格式化为key=value形式
      if (typeof props.requestBody === 'string') {
        if (props.requestBody.includes('=')) {
          // 已经是key=value格式
          return props.requestBody;
        } else {
          // 尝试解析为JSON再转为form格式
          try {
            const jsonObj = JSON.parse(props.requestBody);
            return Object.entries(jsonObj)
              .map(([key, value]) => `${key}=${value}`)
              .join('&');
          } catch (e) {
            return props.requestBody;
          }
        }
      } else if (typeof props.requestBody === 'object') {
        // 对象直接转为form格式
        return Object.entries(props.requestBody)
          .map(([key, value]) => `${key}=${value}`)
          .join('&');
      }
    }
    
    // 默认直接返回原始内容
    return props.requestBody || '';
  } catch (error) {
    return props.requestBody || '';
  }
})

// 计算属性：格式化的响应数据
const formattedResponse = computed(() => {
  if (!responseData.value) return ''
  try {
    return JSON.stringify(responseData.value, null, 2)
  } catch (error) {
    return String(responseData.value)
  }
})

// 计算属性：Content-Type标签
const contentTypeLabel = computed(() => {
  const contentTypeMap = {
    'application/json': 'JSON',
    'application/x-www-form-urlencoded': 'Form',
    'multipart/form-data': 'Form-Data',
    'text/plain': 'Text'
  }
  return contentTypeMap[props.contentType] || props.contentType
})

// 获取滚动容器
const getScrollContainer = () => {
  return document.querySelector(SELECTORS.DRAWER_BODY)
}

// 监听滚动事件
const handleScroll = () => {
  const scrollContainer = getScrollContainer()
  if (scrollContainer) {
    scrollY.value = scrollContainer.scrollTop
    showBackToTop.value = scrollY.value > 300
    
    // 计算是否显示滚动到底部按钮
    const isScrolledToBottom = scrollContainer.scrollHeight - scrollContainer.scrollTop - scrollContainer.clientHeight < 100
    showScrollToBottom.value = !isScrolledToBottom
  }
}

// 返回顶部
const scrollToTop = () => {
  const scrollContainer = getScrollContainer()
  if (scrollContainer) {
    // 方法一：使用scrollTo
    try {
      scrollContainer.scrollTo({
        top: 0,
        behavior: 'smooth'
      })
    } catch (e) {
      console.error('scrollTo方法失败:', e)
    }
    
    // 方法二：直接设置scrollTop (兜底方案)
    setTimeout(() => {
      scrollContainer.scrollTop = 0
      // 更新按钮状态
      handleScroll()
    }, 50)
  }
}

// 滚动到抽屉底部
const scrollToBottomOfDrawer = () => {
  const scrollContainer = getScrollContainer()
  if (scrollContainer) {
    const scrollHeight = scrollContainer.scrollHeight
    
    // 方法一：使用scrollTo
    try {
      scrollContainer.scrollTo({
        top: scrollHeight,
        behavior: 'smooth'
      })
    } catch (e) {
      console.error('scrollTo方法失败:', e)
    }
    
    // 方法二：直接设置scrollTop (兜底方案)
    setTimeout(() => {
      scrollContainer.scrollTop = scrollHeight
      // 更新按钮状态
      handleScroll()
    }, 50)
  }
}

// 自动滚动到底部
const scrollToBottom = (element) => {
  if (element && element.value) {
    element.value.scrollTop = element.value.scrollHeight
  }
}

// 添加日志
const addLog = (message, type = 'info') => {
  const now = new Date()
  const timeStr = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}`
  requestLog.value.push({
    time: timeStr,
    message,
    type
  })
  
  // 添加日志后滚动到底部
  nextTick(() => {
    scrollToBottom(logBlock)
  })
}

// 添加对抽屉状态变化的监听
const setupScrollListener = () => {
  nextTick(() => {
    const scrollContainer = getScrollContainer()
    if (scrollContainer) {
      // 先移除之前可能存在的监听器，避免重复
      scrollContainer.removeEventListener('scroll', handleScroll)
      // 添加新的监听器
      scrollContainer.addEventListener('scroll', handleScroll)
      // 初始化滚动状态
      handleScroll()
    }
  })
}

const cleanupScrollListener = () => {
  const scrollContainer = getScrollContainer()
  if (scrollContainer) {
    scrollContainer.removeEventListener('scroll', handleScroll)
  }
}

// 监听抽屉的打开状态
watch(isDebugDrawerVisible, (newVal) => {
  if (newVal) {
    // 抽屉打开时，延迟设置滚动监听
    setTimeout(setupScrollListener, 300)
  } else {
    // 抽屉关闭时，清理滚动监听
    cleanupScrollListener()
  }
})

// 打开调试抽屉
const openDebugDrawer = () => {
  isDebugDrawerVisible.value = true
  
  // 重置滚动位置和按钮状态
  nextTick(() => {
    // 重置按钮状态
    showBackToTop.value = false
    showScrollToBottom.value = false
  })
}

// 发送调试请求
const sendDebugRequest = async () => {
  if (!props.requestUrl) {
    ElMessage.error('请求URL不能为空')
    return
  }
  
  try {
    isLoading.value = true
    
    // 清空之前的响应数据
    responseData.value = null
    responseStatus.value = null
    responseTime.value = null
    responseHeaders.value = null
    
    // 记录开始时间
    const startTime = new Date().getTime()
    
    // 添加日志
    addLog(`开始发送${props.requestType}请求: ${props.requestUrl}`)
    
    // 创建请求配置
    const config = {
      timeout: 30000,
      headers: {
        'Content-Type': props.contentType
      }
    }
    
    // 处理请求头
    try {
      if (typeof props.requestHeaders === 'string' && props.requestHeaders.trim()) {
        // 如果是字符串，尝试解析为JSON
        const headers = JSON.parse(props.requestHeaders)
        Object.assign(config.headers, headers)
      } else if (typeof props.requestHeaders === 'object') {
        // 如果是对象，直接合并
        Object.assign(config.headers, props.requestHeaders)
      }
    } catch (error) {
      ElMessage.error('请求头格式错误，请检查JSON格式')
      addLog(`请求头解析错误: ${error.message}`, 'error')
      isLoading.value = false
      return
    }
    
    // 处理请求体
    let data = null
    if (['post', 'put', 'patch'].includes(props.requestType.toLowerCase())) {
      try {
        if (typeof props.requestBody === 'string' && props.requestBody.trim()) {
          // 字符串类型的请求体
          if (props.contentType === 'application/json') {
            data = JSON.parse(props.requestBody)
          } else if (props.contentType === 'application/x-www-form-urlencoded') {
            // 处理form表单数据
            const formData = new URLSearchParams()
            const parsed = JSON.parse(props.requestBody)
            for (const key in parsed) {
              formData.append(key, parsed[key])
            }
            data = formData
          } else {
            // 文本内容直接发送
            data = props.requestBody
          }
        } else if (typeof props.requestBody === 'object') {
          // 对象类型的请求体
          if (props.contentType === 'application/x-www-form-urlencoded') {
            // 对象转为表单数据
            const formData = new URLSearchParams()
            for (const key in props.requestBody) {
              formData.append(key, props.requestBody[key])
            }
            data = formData
          } else {
            // JSON或其他格式直接发送对象
            data = props.requestBody
          }
        }
      } catch (error) {
        ElMessage.error('请求体格式错误，请检查内容格式')
        addLog(`请求体解析错误: ${error.message}`, 'error')
        isLoading.value = false
        return
      }
    }
    
    // 创建自定义的axios实例
    const axiosInstance = axios.create(config)
    
    // 发送HTTP请求
    const response = await axiosInstance({
      url: props.requestUrl,
      method: props.requestType,
      data: data
    })
    
    // 计算请求耗时
    const endTime = new Date().getTime()
    const duration = endTime - startTime
    
    // 设置响应数据
    responseData.value = response.data
    responseStatus.value = response.status
    responseTime.value = duration
    responseHeaders.value = response.headers
    
    // 根据状态码添加日志
    if (responseStatus.value >= 200 && responseStatus.value < 300) {
      addLog(`请求成功完成 [${responseStatus.value}], 耗时: ${duration}ms`, 'success')
      ElMessage.success(`请求成功 [${responseStatus.value}]`)
    } else {
      addLog(`请求完成，但状态码异常 [${responseStatus.value}], 耗时: ${duration}ms`, 'warning')
      ElMessage.warning(`请求返回非成功状态码 [${responseStatus.value}]`)
    }
    
    // 自动切换到响应标签页
    responseTab.value = 'data'
    
    // 等待DOM更新完成后滚动到响应区域
    nextTick(() => {
      // 尝试滚动到响应区域
      setTimeout(() => {
        // 先尝试按class查找响应区域
        const responseElement = document.querySelector(SELECTORS.RESPONSE_SECTION)
        if (responseElement) {
          responseElement.scrollIntoView({ behavior: 'smooth', block: 'start' })
          
          // 更新滚动按钮状态
          setTimeout(() => {
            handleScroll()
            
            // 特别检查响应区块是否存在并进一步滚动到它
            const responseBlock = document.querySelector(SELECTORS.RESPONSE_AREA)
            if (responseBlock) {
              responseBlock.scrollIntoView({ behavior: 'smooth', block: 'start' })
            }
          }, 300)
        }
      }, 100)
    })
  } catch (error) {
    console.error('请求错误:', error)
    
    // 设置错误响应
    responseStatus.value = error.response?.status || 0
    responseData.value = error.response?.data || { error: error.message }
    responseTime.value = 0
    responseHeaders.value = error.response?.headers || {}
    
    // 添加错误日志
    addLog(`请求失败: ${error.message}`, 'error')
    ElMessage.error(`请求失败: ${error.message}`)
    
    // 更新滚动按钮状态
    setTimeout(handleScroll, 500)
  } finally {
    isLoading.value = false
  }
}

// 格式化响应头为可迭代对象
const formatHeaders = (headers) => {
  if (typeof headers === 'object' && headers !== null) {
    // 如果已经是对象，则直接返回
    return headers;
  }
  
  try {
    // 尝试解析JSON字符串
    if (typeof headers === 'string') {
      return JSON.parse(headers);
    }
  } catch (error) {
    console.error('解析响应头失败:', error);
  }
  
  return {}; // 默认返回空对象
}

// 添加生命周期钩子
onMounted(() => {
  // 抽屉已经存在时才进行初始化
  if (isDebugDrawerVisible.value) {
    setupScrollListener()
  }
})

onUnmounted(() => {
  // 清理滚动监听器
  cleanupScrollListener()
})

defineExpose({
  openDebugDrawer
})
</script>

<style scoped>
.debug-drawer-content {
  padding: 10px;
}

.debug-section {
  margin-bottom: 20px;
}

.debug-section h3 {
  margin-bottom: 10px;
  font-size: 16px;
  font-weight: bold;
}

.debug-info, .response-info {
  background-color: #f5f7fa;
  border-radius: 4px;
  padding: 10px;
}

.debug-info p, .response-info p {
  margin: 5px 0;
}

.debug-code-block {
  background-color: #f5f7fa;
  border-radius: 4px;
  padding: 10px;
  overflow-x: auto;
  min-height: 100px;
}

.debug-code-block pre {
  margin: 0;
  white-space: pre-wrap;
}

.response-block {
  max-height: 300px;
  overflow-y: auto;
}

.success-status {
  color: #67c23a;
  font-weight: bold;
}

.error-status {
  color: #f56c6c;
  font-weight: bold;
}

.header-item {
  padding: 5px 0;
  border-bottom: 1px dashed #e0e0e0;
}

.header-item:last-child {
  border-bottom: none;
}

:deep(.el-tabs__header) {
  margin-bottom: 10px;
}

:deep(.el-tabs__item) {
  font-size: 14px;
  height: 40px;
  line-height: 40px;
}

:deep(.el-tabs__nav-wrap::after) {
  height: 1px;
}

.debug-log-block {
  background-color: #292d3e;
  color: #eeffff;
  border-radius: 4px;
  padding: 10px;
  font-family: 'Courier New', monospace;
  font-size: 12px;
  min-height: 100px;
  max-height: 200px;
  overflow-y: auto;
}

.debug-log-block p {
  margin: 3px 0;
  line-height: 1.5;
}

.log-time {
  color: #c792ea;
  margin-right: 5px;
}

.info {
  color: #82aaff;
}

.success {
  color: #c3e88d;
}

.warning {
  color: #ffcb6b;
}

.error {
  color: #f07178;
}

.scroll-buttons {
  position: fixed;
  bottom: 160px;
  right: 20px;
  display: flex;
  flex-direction: column;
  gap: 10px;
  z-index: 9999;
}

.back-to-top,
.scroll-to-bottom {
  width: 44px;
  height: 44px;
  background-color: #409eff;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.2);
  transition: transform 0.2s, background-color 0.3s;
}

.back-to-top:hover,
.scroll-to-bottom:hover {
  background-color: #66b1ff;
  transform: scale(1.1);
}

.back-to-top:active,
.scroll-to-bottom:active {
  transform: scale(0.95);
  background-color: #3a8ee6;
}

.back-to-top .el-icon,
.scroll-to-bottom .el-icon {
  color: #fff;
  font-size: 24px;
}

.float-debug-btn {
  position: fixed;
  right: 20px;
  bottom: 80px;
  z-index: 999;
  display: flex;
  align-items: center;
  cursor: pointer;
}

.float-debug-btn .el-button {
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
  width: 56px;
  height: 56px;
  transition: all 0.3s;
  background-color: #409eff;
  border-color: #409eff;
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0% {
    box-shadow: 0 0 0 0 rgba(64, 158, 255, 0.7);
  }
  70% {
    box-shadow: 0 0 0 10px rgba(64, 158, 255, 0);
  }
  100% {
    box-shadow: 0 0 0 0 rgba(64, 158, 255, 0);
  }
}

.float-debug-btn:hover .el-button {
  transform: scale(1.1);
  background-color: #66b1ff;
  border-color: #66b1ff;
  box-shadow: 0 6px 16px rgba(0, 0, 0, 0.2);
  animation: none; /* 悬停时停止动画 */
}

.float-debug-btn:active .el-button {
  transform: scale(0.95);
  background-color: #3a8ee6;
  border-color: #3a8ee6;
}

.float-debug-btn .el-icon {
  font-size: 24px;
  color: #fff;
}

.btn-tooltip {
  position: absolute;
  right: 66px;
  background-color: rgba(48, 49, 51, 0.9);
  color: white;
  padding: 6px 12px;
  border-radius: 4px;
  font-size: 14px;
  opacity: 0;
  visibility: hidden;
  transition: all 0.3s;
  white-space: nowrap;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
}

.float-debug-btn:hover .btn-tooltip {
  opacity: 1;
  visibility: visible;
}

/* 响应式设计 */
@media screen and (max-width: 768px) {
  .float-debug-btn {
    right: 15px;
    bottom: 70px;
  }
  
  .float-debug-btn .el-button {
    width: 48px;
    height: 48px;
  }
  
  .btn-tooltip {
    right: 58px;
    font-size: 12px;
    padding: 4px 8px;
  }
  
  .scroll-buttons {
    bottom: 130px;
    right: 15px;
  }
  
  .back-to-top,
  .scroll-to-bottom {
    width: 40px;
    height: 40px;
  }
}
</style> 